home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CBASE102.ARJ / CBDDLP.Y < prev    next >
Text File  |  1991-09-23  |  25KB  |  885 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* definition section --------------------------------------------------------*/
  5. %{
  6. /* #ident    "@(#)cbddlp.y    1.6 - 91/09/23" */
  7.  
  8. #include <ansi.h>
  9.  
  10. /* local headers */
  11. #include "cbddlp.h"
  12.  
  13. #ifdef DEBUG
  14. #define DBPRINT {                            \
  15.     fprintf(stderr, "%s[%d].\n", __FILE__, __LINE__);        \
  16. }
  17. #else
  18. #define DBPRINT
  19. #endif
  20.  
  21. %}
  22.  
  23. /* declaration section -------------------------------------------------------*/
  24. %union {
  25.     int    keyword;
  26.     char *    buf;
  27. }
  28. %token    <keyword>    COMPOUND CONTAINS DATAFILE KEY INDEXFILE RECORD UNIQUE
  29. %token    <buf>        ELEMC IDENTIFIER STRING
  30.  
  31. /* rule section --------------------------------------------------------------*/
  32. %%
  33. /* data definition language */
  34. ddl    : stmt
  35.     | ddl stmt
  36.     ;
  37.  
  38. /* generic statement */
  39. stmt    : /* blank line */
  40.     | datafile
  41.     | indexfile
  42.     | record
  43.     ;
  44.  
  45. /* date file statement */
  46. datafile: DATAFILE STRING CONTAINS IDENTIFIER ';' {
  47. #ifdef DEBUG
  48.         fprintf(stderr, "Line %d: DATAFILE \"%s\" CONTAINS %s;\n", yylineno, $2, $4);
  49. #endif
  50.         /* add slot to data file table */
  51.         ddldfv = (ddldf_t *)realloc(ddldfv, (dfc + 1) * sizeof(*ddldfv));
  52.         if (ddldfv == NULL) {
  53.             yyerror("out of memory");
  54.             return -1;
  55.         }
  56.         memset(ddldfv + dfc, 0, sizeof(*ddldfv));
  57.         ddldfv[dfc].filename = $2;
  58.         ddldfv[dfc].record = $4;
  59.         ++dfc;
  60.     }
  61.     ;
  62.  
  63. /* index file statement */
  64. indexfile: INDEXFILE STRING CONTAINS IDENTIFIER ';' {
  65. #ifdef DEBUG
  66.         fprintf(stderr, "Line %d: INDEXFILE \"%s\" CONTAINS %s;\n", yylineno, $2, $4);
  67. #endif
  68.         /* add slot to index file table */
  69.         ddlifv = (ddlif_t *)realloc(ddlifv, (ifc + 1) * sizeof(*ddlifv));
  70.         if (ddlifv == NULL) {
  71.             yyerror("out of memory");
  72.             return -1;
  73.         }
  74.         memset(ddlifv + ifc, 0, sizeof(*ddlifv));
  75.         ddlifv[ifc].filename = $2;
  76.         ddlifv[ifc].key = $4;
  77.         ++ifc;
  78.     }
  79.     ;
  80.  
  81. /* record statement */
  82. record    : RECORD IDENTIFIER '{' fldlst '}' ';' {
  83.         int fld = 0;
  84. #ifdef DEBUG
  85.         fprintf(stderr, "Line %d: RECORD %s { fldlst };\n", yylineno, $2);
  86. #endif
  87.         recname = $2;
  88.         ddlputh(hfp, recname, fldc, ddlfldv);
  89.         ddlputi(ifp, recname, fldc, ddlfldv);
  90.         /* free memory allocated for current record */
  91.         free(recname);
  92.         recname = NULL;
  93.         for (fld = 0; fld < fldc; ++fld) {
  94.             ddlfldv[fld].flags = 0;
  95.             free(ddlfldv[fld].type);
  96.             ddlfldv[fld].type = NULL;
  97.             if (isalloc(ddlfldv[fld].ctype)) {
  98.                 free(ddlfldv[fld].ctype);
  99.             }
  100.             ddlfldv[fld].ctype = NULL;
  101.             free(ddlfldv[fld].name);
  102.             ddlfldv[fld].name = NULL;
  103.             if (ddlfldv[fld].elemc != NULL) free(ddlfldv[fld].elemc);
  104.             ddlfldv[fld].elemc = NULL;
  105.         }
  106.         fldc = 0;
  107.     }
  108.     ;
  109.  
  110. /* field list */
  111. fldlst    : fld
  112.     | fldlst fld
  113.     ;
  114.  
  115. /* field */
  116. fld    : fqlst IDENTIFIER IDENTIFIER ELEMC ';' {
  117. #ifdef DEBUG
  118.         fprintf(stderr, "Line %d: fqlst %s %s [%s];\n", yylineno, $2, $3, $4);
  119. #endif
  120.         /* add slot to field table */
  121.         ddlfldv = (ddlfld_t *)realloc(ddlfldv, (fldc + 2) * sizeof(*ddlfldv));
  122.         if (ddlfldv == NULL) {
  123.             yyerror("out of memory");
  124.             return -1;
  125.         }
  126.         memset(ddlfldv + fldc + 1, 0, sizeof(*ddlfldv));
  127.         ddlfldv[fldc].type = $2;
  128.         ddlfldv[fldc].ctype = ctype(ddlfldv[fldc].type);
  129.         if (ddlfldv[fldc].ctype == NULL) {
  130.             yyerror("Undefined cbase data type");
  131.             return -1;
  132.         }
  133.         ddlfldv[fldc].name = $3;
  134.         ddlfldv[fldc].elemc = $4;
  135.         ++fldc;
  136.     }
  137.     | fqlst IDENTIFIER IDENTIFIER ';' {
  138. #ifdef DEBUG
  139.         fprintf(stderr, "Line %d: fqlst %s %s;\n", yylineno, $2, $3);
  140. #endif
  141.         /* add slot to field table */
  142.         ddlfldv = (ddlfld_t *)realloc(ddlfldv, (fldc + 2) * sizeof(*ddlfldv));
  143.         if (ddlfldv == NULL) {
  144.             yyerror("out of memory");
  145.             return -1;
  146.         }
  147.         memset(ddlfldv + fldc + 1, 0, sizeof(*ddlfldv));
  148.         ddlfldv[fldc].type = $2;
  149.         ddlfldv[fldc].ctype = ctype(ddlfldv[fldc].type);
  150.         if (ddlfldv[fldc].ctype == NULL) {
  151.             yyerror("Undefined cbase data type");
  152.             return -1;
  153.         }
  154.         ddlfldv[fldc].name = $3;
  155.         ddlfldv[fldc].elemc = NULL;
  156.         ++fldc;
  157.     }
  158.     | fqlst IDENTIFIER ':' IDENTIFIER IDENTIFIER ELEMC ';' {
  159. #ifdef DEBUG
  160.         fprintf(stderr, "Line %d: fqlst %s:%s %s %s;\n", yylineno, $2, $4, $5, $6);
  161. #endif
  162.         /* add slot to field table */
  163.         ddlfldv = (ddlfld_t *)realloc(ddlfldv, (fldc + 2) * sizeof(*ddlfldv));
  164.         if (ddlfldv == NULL) {
  165.             yyerror("out of memory");
  166.             return -1;
  167.         }
  168.         memset(ddlfldv + fldc + 1, 0, sizeof(*ddlfldv));
  169.         ddlfldv[fldc].type = $2;
  170.         ddlfldv[fldc].ctype = $4;
  171.         ddlfldv[fldc].name = $5;
  172.         ddlfldv[fldc].elemc = $6;
  173.         ++fldc;
  174.     }
  175.     | fqlst IDENTIFIER ':' IDENTIFIER IDENTIFIER ';' {
  176.         /* add slot to field table */
  177.         ddlfldv = (ddlfld_t *)realloc(ddlfldv, (fldc + 2) * sizeof(*ddlfldv));
  178.         if (ddlfldv == NULL) {
  179.             yyerror("out of memory");
  180.             return -1;
  181.         }
  182.         memset(ddlfldv + fldc + 1, 0, sizeof(*ddlfldv));
  183.         ddlfldv[fldc].type = $2;
  184.         ddlfldv[fldc].ctype = $4;
  185.         ddlfldv[fldc].name = $5;
  186.         ddlfldv[fldc].elemc = NULL;
  187.         ++fldc;
  188.     }
  189.     ;
  190.  
  191. /* field qualifier list */
  192. fqlst    : /* none */
  193.     | fqlst fq
  194.     ;
  195.  
  196. /* field qualifier */
  197. fq    : COMPOUND {
  198. #ifdef DEBUG
  199.         fprintf(stderr, "Line %d: COMPOUND\n", yylineno);
  200. #endif
  201.         yyerror("compound keys not yet implemented");
  202.         return -1;
  203.     }
  204.     | KEY {
  205. #ifdef DEBUG
  206.         fprintf(stderr, "Line %d: KEY\n", yylineno);
  207. #endif
  208.         ddlfldv[fldc].flags |= CB_FKEY;
  209.     }
  210.     | UNIQUE {
  211. #ifdef DEBUG
  212.         fprintf(stderr, "Line %d: UNIQUE\n", yylineno);
  213. #endif
  214.         ddlfldv[fldc].flags |= CB_FUNIQ;
  215.     }
  216.     ;
  217. %%
  218.  
  219. /* subroutine section --------------------------------------------------------*/
  220. /* ansi headers */
  221. #include <errno.h>
  222. #ifdef AC_STDDEF
  223. #include <stddef.h>
  224. #endif
  225. #include <stdio.h>
  226. #ifdef AC_STDLIB
  227. #include <stdlib.h>
  228. #endif
  229. #ifdef AC_STRING
  230. #include <string.h>
  231. #endif
  232.  
  233. /* library headers */
  234. #include <bool.h>
  235. #include <cbase.h>
  236.  
  237. /* local headers */
  238. #include "basstr.h"
  239. #include "cbddlp.h"
  240.  
  241. /* constants */
  242. #define PROGNAME    "cbddlp"        /* default program name */
  243. #define USAGE        "usage: %s ddlfile\n"    /* usage message */
  244.  
  245. /* global definitions */
  246. char *        progname    = PROGNAME;    /* program name */
  247. FILE *        hfp        = NULL;        /* .h file stream */
  248. FILE *        ifp        = NULL;        /* .i file stream */
  249. char *        recname        = NULL;        /* record name */
  250. int        dfc        = 0;        /* data file count */
  251. ddldf_t    *    ddldfv        = NULL;        /* ddl data file table */
  252. int        ifc        = 0;        /* index file count */
  253. ddlif_t    *    ddlifv        = NULL;        /* ddl index file table */
  254. int        fldc        = 0;        /* field count */
  255. ddlfld_t *    ddlfldv        = NULL;        /* ddl field table */
  256. const char * const typtbl[] = {            /* cbase/C data type table */
  257.     "t_char",    "char",            /*  0 */
  258.     "t_charv",    "char",            /*  1 */
  259.     "t_uchar",    "unsigned char",    /*  2 */
  260.     "t_ucharv",    "unsigned char",    /*  3 */
  261.     "t_short",    "short",        /*  4 */
  262.     "t_shortv",    "short",        /*  5 */
  263.     "t_ushort",    "unsigned short",    /*  6 */
  264.     "t_ushortv",    "unsigned short",    /*  7 */
  265.     "t_int",    "int",            /*  8 */
  266.     "t_intv",    "int",            /*  9 */
  267.     "t_uint",    "unsigned int",        /* 10 */
  268.     "t_uintv",    "unsigned int",        /* 11 */
  269.     "t_long",    "long",            /* 12 */
  270.     "t_longv",    "long",            /* 13 */
  271.     "t_ulong",    "unsigned long",    /* 14 */
  272.     "t_ulongv",    "unsigned long",    /* 15 */
  273.     "t_float",    "float",        /* 16 */
  274.     "t_floatv",    "float",        /* 17 */
  275.     "t_double",    "double",        /* 18 */
  276.     "t_doublev",    "double",        /* 19 */
  277.     "t_ldouble",    "long double",        /* 20 */
  278.     "t_ldoublev",    "long double",        /* 21 */
  279.     "t_pointer",    "void *",        /* 22 */
  280.     "t_pointerv",    "void *",        /* 23 */
  281.     "t_string",    "char",            /* 24 */
  282.     "t_cistring",    "char",            /* 25 */
  283.     "t_binary",    "unsigned char",    /* 26 */
  284. };
  285.  
  286. /*man---------------------------------------------------------------------------
  287. NAME
  288.      cbddlp - cbase data definition language processor
  289.  
  290. SYNOPSIS
  291.      cbddlp ddlfile
  292.  
  293. DESCRIPTION
  294.      The cbddlp command processes cbase data definition language (DDL)
  295.      files.  A cbase database can be specified in a DDL file, which is
  296.      then processed using cbddlp to generate the C files required by
  297.      cbase to manipulate that database.  cbddlp requires that DDL
  298.      files have the suffix ".ddl".  The C files generated are given
  299.      the same name as the DDL file except for the suffix; a .h and a
  300.      .i file are generated.  The .h file must be included by every
  301.      module accessing the database, while the .i file must be included
  302.      by exactly one module of every program that accesses the database.
  303.  
  304.      There are three types of DDL statements:  data file, index file,
  305.      and record.  The syntax for the record statement is
  306.  
  307.           record recname {
  308.                [[unique ]key] dbtype fldname[\\[elemc\\]];
  309.                ...
  310.           };
  311.  
  312.      recname is the name of the record.  dbtype is the database data
  313.      type of the field.  fldname is the name of the field, and must be
  314.      unique for a given database.  elemc specifies the number of
  315.      elements for array data types; this may be any C expression valid
  316.      for defining the size of a static array.  The key keyword
  317.      specifies that an index is to be maintained on this field.  The
  318.      unique keyword specifies that the keys in this index must be
  319.      unique.  Multiple records can be defined in the same DDL file.
  320.  
  321.      User-defined data types may also be specified in a DDL file, but
  322.      require an additional piece of information.  For the predefined
  323.      data types, cbddlp knows what the corresponding C data type is
  324.      (t_string : char, t_int : int, etc.).  But for user-defined data
  325.      types, this must be explicitly specified.  The syntax for this is
  326.      as follows.
  327.  
  328.           [[unique ]key] dbtype:ctype fldname[\[elemc\]];
  329.  
  330.      where dbtype is a user-defined database data type and ctype is
  331.      the corresponding C data type.  ctype must consist of only one
  332.      identifier; if the C data type consists of multiple identifiers
  333.      (e.g., long double), either #define or typedef must be used to
  334.      reduce it to one identifier (e.g., typedef long double ldouble).
  335.  
  336.      The syntax for the data file statement is
  337.  
  338.           data file "filename" contains recname;
  339.  
  340.      filename is the name of the file in which recname records are to
  341.      be stored.  The data file statement must precede its associated
  342.      record statement.
  343.  
  344.      The syntax for the index file statement is
  345.  
  346.           index file "filename" contains keyname;
  347.  
  348.      filename is the name of the file in which keyname keys are to be
  349.      indexed.  The index file statement must precede the record
  350.      statement containing the associated key.
  351.  
  352.      C comments may appear in DDL files wherever white space is
  353.      allowed, with the exception of within the keyword pairs "data
  354.      file" and "index file".  C preprocessor statements may also be
  355.      placed in DDL files, but cannot currently span multiple lines,
  356.      nor can comments on the same line as a preprocessor statement;
  357.      any line beginning with the # character (excluding any leading
  358.      white space) will be passed directly through to the generated .h
  359.      file.
  360.  
  361.      In the headers generated by cbddlp, a macro for the record name
  362.      is constructed by converting all lower case letters in the record
  363.      name to capitals.  A macro is also defined for each field in the
  364.      same fashion.  The initial characters (up to four) of the first
  365.      field name of a record preceding the first underscore are used as
  366.      a prefix for the field count macro and field definition list.
  367.      This prefix must be unique for all records in a database.  The
  368.      field count macro identifier is constructed by converting this
  369.      prefix to capitals and appending FLDC.  The field definition list
  370.      identifier is constructed by appending fldv to the prefix.
  371.  
  372. EXAMPLE
  373.      Below is given an example DDL file for a rolodeck database
  374.      consisting of a single record.
  375.  
  376.      /* constants *\/
  377.      #define NAME_MAX     (40)   /* max name length *\/
  378.      #define ADDR_MAX     (40)   /* max address length *\/
  379.      #define NOTELIN_MAX   (4)   /* note lines *\/
  380.      #define NOTECOL_MAX  (40)   /* note columns *\/
  381.  
  382.      /* file assignments *\/
  383.      data file  "rolodeck.dat" contains rolodeck;
  384.      index file "rdcont.ndx"   contains rd_contact;
  385.      index file "rdcomp.ndx"   contains rd_company;
  386.  
  387.      record rolodeck {                        /* rolodeck record *\/
  388.          unique key t_string
  389.                       rd_contact[NAME_MAX];   /* contact name *\/
  390.          t_string     rd_title[41];           /* contact title *\/
  391.          key t_string rd_company[NAME_MAX];   /* company name *\/
  392.          t_string     rd_addr[81];            /* address *\/
  393.          t_string     rd_city[26];            /* city *\/
  394.          t_string     rd_state[3];            /* state *\/
  395.          t_string     rd_zip[11];             /* zip code *\/
  396.          t_string     rd_phone[13];           /* phone number *\/
  397.          t_string     rd_ext[5];              /* phone extension *\/
  398.          t_string     rd_fax[13];             /* fax number *\/
  399.          t_string     rd_notes[NOTELIN_MAX * NOTECOL_MAX];
  400.                                               /* notes *\/
  401.      };
  402.  
  403.      If the name of this DDL file was rolodeck.ddl, the generated C
  404.      files would be rolodeck.h and rolodeck.i.  The cbase name macro
  405.      would be ROLODECK (the record identifier capitalized).  The field
  406.      count macro would be RDFLDC, and the field definition list would
  407.      be rdfldv.  The rolodeck would be therefore be opened (for
  408.      writing) with the C statement
  409.  
  410.           cbopen(ROLODECK, "r+", RDFLDC, rdfldv);
  411.  
  412.      The phone number from the current record would be read from the
  413.      database with
  414.  
  415.          cbgetrf(cbp, RD_PHONE, buf);
  416.  
  417.  
  418. NOTES
  419.      For a make utility to automatically process DDL files without an
  420.      explicit rule for each one, suffix rules defining the creation of
  421.      the data definition header files from a DDL file can be added to
  422.      the makefile.  For the standard UNIX make, the following
  423.      instructions would be inserted near the beginning of the
  424.      makefile.
  425.  
  426.      # suffix rules
  427.      .SUFFIXES:  .ddl .h .i
  428.  
  429.      .ddl.h:
  430.           cbddlp $<
  431.  
  432.      .ddl.i:
  433.           cbddlp $<
  434.  
  435.      The exact procedure for other make utilities varies.
  436.  
  437. ------------------------------------------------------------------------------*/
  438. #ifdef AC_PROTO
  439. int main(int argc, char *argv[])
  440. #else
  441. int main(argc, argv)
  442. int argc;
  443. char *argv[];
  444. #endif
  445. {
  446.     char *    dbname        = NULL;        /* database name */
  447.     char *    udbname        = NULL;        /* upper case database name */
  448.     char *    ddlfile        = NULL;        /* ddl filename */
  449.     FILE *    ddlfp        = NULL;        /* ddl file stream */
  450.     char *    hfile        = NULL;        /* .h filename */
  451.     char *    ifile        = NULL;        /* .i filename */
  452.     size_t    len        = 0;        /* string length */
  453.     char *    p1        = NULL;        /* gp pointers */
  454.     char *    p2        = NULL;
  455.  
  456.     /* process command line */
  457.     if (argc > 0) {            /* program name */
  458.         progname = *argv;
  459.         --argc;
  460.         ++argv;
  461.     }
  462.     if (argc < 1) {            /* ddl filename */
  463.         fprintf(stderr, USAGE, progname);
  464.         exit(EXIT_FAILURE);
  465.     }
  466.     ddlfile = *argv;
  467.     --argc;
  468.     ++argv;
  469.     if (argc != 0) {
  470.         fprintf(stderr, USAGE, progname);
  471.         exit(EXIT_FAILURE);
  472.     }
  473.  
  474.     /* construct output filenames */
  475.     p1 = strrchr(ddlfile, PATHDLM);        /* remove path prefix */
  476.     if (p1 == NULL) {
  477.         p1 = ddlfile;
  478.     } else {
  479.         ++p1;
  480.     }
  481.     p2 = strrchr(p1, '.');            /* remove dot suffix */
  482.     if (p2 == NULL) {
  483.         fprintf(stderr, "%s: Input file must have .ddl suffix.\n", progname);
  484.         exit(EXIT_FAILURE);
  485.     }
  486.     if (strcmp(p2, ".ddl") != 0) {
  487.         fprintf(stderr, "%s: Input file must have .ddl suffix.\n", progname);
  488.         exit(EXIT_FAILURE);
  489.     }
  490.     len = p2 - p1;                /* length w/o suffix */
  491.     hfile = (char *)malloc(len + 2 + 1);    /* .h file name */
  492.     if (hfile == NULL) {
  493.         perror("out of memory");
  494.         exit(EXIT_FAILURE);
  495.     }
  496.     strncpy(hfile, p1, len);
  497.     strncpy(hfile + len, ".h", 2);
  498.     hfile[len + 2] = NUL;
  499.     ifile = (char *)malloc(len + 2 + 1);    /* .i file name */
  500.     if (ifile == NULL) {
  501.         perror("out of memory");
  502.         exit(EXIT_FAILURE);
  503.     }
  504.     strncpy(ifile, p1, len);
  505.     strncpy(ifile + len, ".i", 2);
  506.     ifile[len + 2] = NUL;
  507.     dbname = (char *)malloc(len + 1);    /* database name */
  508.     if (dbname == NULL) {
  509.         perror("out of memory");
  510.         exit(EXIT_FAILURE);
  511.     }
  512.     strncpy(dbname, p1, len);
  513.     dbname[len] = NUL;
  514.     udbname = (char *)malloc(len + 1);    /* upper case database name */
  515.     if (udbname == NULL) {
  516.         perror("out of memory");
  517.         exit(EXIT_FAILURE);
  518.     }
  519.     cvtss(udbname, dbname, CVT_UPPER, len);
  520.     udbname[len] = NUL;
  521.  
  522.     /* allocate first slot in each ddl table */
  523.     ddldfv = (ddldf_t *)calloc((size_t)1, sizeof(*ddldfv));
  524.                             /* data file table */
  525.     if (ddldfv == NULL) {
  526.         perror("out of memory");
  527.         exit(EXIT_FAILURE);
  528.     }
  529.     ddlifv = (ddlif_t *)calloc((size_t)1, sizeof(*ddlifv));
  530.                             /* index file table */
  531.     if (ddlifv == NULL) {
  532.         perror("out of memory");
  533.         exit(EXIT_FAILURE);
  534.     }
  535.     ddlfldv = (ddlfld_t *)calloc((size_t)1, sizeof(*ddlfldv));
  536.                             /* field table */
  537.     if (ddlfldv == NULL) {
  538.         perror("out of memory");
  539.         exit(EXIT_FAILURE);
  540.     }
  541.  
  542.     /* open files */
  543.     ddlfp = fopen(ddlfile, "r");            /* ddl file */
  544.     if (ddlfp == NULL) {
  545.         perror("opening ddl file");
  546.         exit(EXIT_FAILURE);
  547.     }
  548.     hfp = fopen(hfile, "w");            /* .h file */
  549.     if (hfp == NULL) {
  550.         perror("opening .h file");
  551.         exit(EXIT_FAILURE);
  552.     }
  553.     ifp = fopen(ifile, "w");            /* .i file */
  554.     if (ifp == NULL) {
  555.         perror("opening .i file");
  556.         exit(EXIT_FAILURE);
  557.     }
  558.  
  559.     /* redirect lex input to ddl stream */
  560.     yyin = ddlfp;
  561.  
  562.     /* write multiple include #ifndefs */
  563.     fprintf(hfp, "#ifndef H_%s\t/* prevent multiple includes */\n", udbname);
  564.     fprintf(hfp, "#define H_%s\n\n", udbname);
  565.     fprintf(ifp, "#ifndef I_%s\t/* prevent multiple includes */\n", udbname);
  566.     fprintf(ifp, "#define I_%s\n\n", udbname);
  567.  
  568.     /* write #includes */
  569.     fputs("/* libray headers */\n", hfp);        /* .h file */
  570.     fputs("#include <cbase.h>\n\n", hfp);
  571.     fputs("#include <ansi.h>\n", ifp);        /* .i file */
  572.     fputs("\n/* ansi headers */\n", ifp);
  573.     fputs("#ifdef AC_STDDEF\n", ifp);
  574.     fputs("#include <stddef.h>\n", ifp);
  575.     fputs("#endif\n", ifp);
  576.     fputs("\n/* libray headers */\n", ifp);
  577.     fputs("#include <cbase.h>\n", ifp);
  578.     fputs("\n/* local headers */\n", ifp);
  579.     fprintf(ifp, "#include \"%s\"\n\n", hfile);
  580.  
  581.     /* process ddl file */
  582.     if (yyparse()) {
  583.         fprintf(stderr, "Fatal error processing %s.\n", ddlfile);
  584.         exit(EXIT_FAILURE);
  585.     }
  586.     if (ferror(hfp)) {
  587.         fprintf(stderr, "Error writing %s: ", hfile);
  588.         perror("");
  589.         exit(EXIT_FAILURE);
  590.     }
  591.     if (ferror(ifp)) {
  592.         fprintf(stderr, "Error writing %s: ", ifile);
  593.         perror("");
  594.         exit(EXIT_FAILURE);
  595.     }
  596.  
  597.     /* write multiple include #endifs */
  598.     fprintf(hfp, "#endif    /* #ifndef H_%s */\n", udbname);
  599.     fprintf(ifp, "#endif    /* #ifndef I_%s */\n", udbname);
  600.  
  601.     /* close files */
  602.     if (fclose(ddlfp) == EOF) {
  603.         fprintf(stderr, "Error closing %s: ", ddlfile);
  604.         perror("");
  605.         exit(EXIT_FAILURE);
  606.     }
  607.     if (fclose(hfp) == EOF) {
  608.         fprintf(stderr, "Error closing %s: ", hfile);
  609.         perror("");
  610.         exit(EXIT_FAILURE);
  611.     }
  612.     if (fclose(ifp) == EOF) {
  613.         fprintf(stderr, "Error closing %s: ", ifile);
  614.         perror("");
  615.         exit(EXIT_FAILURE);
  616.     }
  617.  
  618.     exit(EXIT_SUCCESS);
  619. }
  620.  
  621. /* ctype:  get C data type from cbase data type */
  622. #ifdef AC_PROTO
  623. char *ctype(const char *type)
  624. #else
  625. char *ctype(type)
  626. const char *type;
  627. #endif
  628. {
  629.     int i = 0;
  630.  
  631.     for (i = 0; i < nelems(typtbl); i += 2) {
  632.         if (strcmp(typtbl[i], type) == 0) {
  633.             return typtbl[i + 1];
  634.         }
  635.     }
  636.  
  637.     return NULL;
  638. }
  639.  
  640. /* fpctype:  put C type */
  641. #ifdef AC_PROTO
  642. int fpctype(FILE *fp, const char *type)
  643. #else
  644. int fpctype(fp, type)
  645. FILE *fp;
  646. const char *type;
  647. #endif
  648. {
  649.     int i = 0;
  650.  
  651.     for (i = 0; i < nelems(typtbl); i += 2) {
  652.         if (strcmp(typtbl[i], type) == 0) {
  653.             fputs(typtbl[i + 1], fp);
  654.             return 0;
  655.         }
  656.     }
  657.  
  658.     return -1;
  659. }
  660.  
  661. /* fpdatafile:  file print data file name */
  662. #ifdef AC_PROTO
  663. int fpdatafile(FILE *fp, const char *recname)
  664. #else
  665. int fpdatafile(fp, recname)
  666. FILE *fp;
  667. const char *recname;
  668. #endif
  669. {
  670.     int i = 0;
  671.  
  672.     for (i = 0; i < dfc; ++i) {
  673.         if (strcmp(ddldfv[i].record, recname) == 0) {
  674.             fprintf(fp, ddldfv[i].filename);
  675.             return 0;
  676.         }
  677.     }
  678.  
  679.     return -1;
  680. }
  681.  
  682. /* fpndxfile:  file print index file name */
  683. #ifdef AC_PROTO
  684. int fpndxfile(FILE *fp, const char *keyname)
  685. #else
  686. int fpndxfile(fp, keyname)
  687. FILE *fp;
  688. const char *keyname;
  689. #endif
  690. {
  691.     int i = 0;
  692.  
  693.     for (i = 0; i < ifc; ++i) {
  694.         if (strcmp(ddlifv[i].key, keyname) == 0) {
  695.             fprintf(fp, ddlifv[i].filename);
  696.             return 0;
  697.         }
  698.     }
  699.  
  700.     return -1;
  701. }
  702.  
  703. /* isalloc:  is ctype allocated? */
  704. #ifdef AC_PROTO
  705. bool isalloc(const char *ctype)
  706. #else
  707. bool isalloc(ctype)
  708. const char *ctype;
  709. #endif
  710. {
  711.     int i = 0;
  712.  
  713.     for (i = 1; i < nelems(typtbl); i += 2) {
  714.         if (typtbl[i] == ctype) {
  715.             return FALSE;
  716.         }
  717.     }
  718.  
  719.     return TRUE;
  720. }
  721.  
  722. /* tmpupr:  temporary upper case string conversion */
  723. #ifdef AC_PROTO
  724. char *tmpupr(const char *s)
  725. #else
  726. char *tmpupr(s)
  727. const char *s;
  728. #endif
  729. {
  730.     static char uprstr[81];
  731.  
  732.     cvtss(uprstr, s, CVT_UPPER, sizeof(uprstr));
  733.     uprstr[sizeof(uprstr) - 1] = NUL;
  734.  
  735.     return uprstr;
  736. }
  737.  
  738. /* warning:  print warning message */
  739. #ifdef AC_PROTO
  740. void warning(const char *s, const char *t)
  741. #else
  742. void warning(s, t)
  743. const char *s;
  744. const char *t;
  745. #endif
  746. {
  747.     fprintf(stderr, "%s: %s", progname, s);
  748.     if (t != NULL) {
  749.         fprintf(stderr, " %s", t);
  750.     }
  751.     fprintf(stderr, " near line %d.\n", yylineno);
  752.  
  753.     return;
  754. }
  755.  
  756. /* yyerror:  yacc error message */
  757. #ifdef AC_PROTO
  758. int yyerror(const char *s)
  759. #else
  760. int yyerror(s)
  761. const char *s;
  762. #endif
  763. {
  764.     warning(s, NULL);
  765.  
  766.     return 0;
  767. }
  768.  
  769. /* global data for ddlput functions */
  770. static char    prefix[PREFIX_MAX + 1];        /* identifier prefix */
  771. static char    uprefix[PREFIX_MAX + 1];    /* prefix in upper case */
  772.  
  773. /* ddlputh:  write to .h file */
  774. #ifdef AC_PROTO
  775. int ddlputh(FILE *fp, const char *recname, int fldc, const ddlfld_t fldv[])
  776. #else
  777. int ddlputh(fp, recname, fldc, fldv)
  778. FILE *fp;
  779. const char *recname;
  780. int fldc;
  781. const ddlfld_t fldv[];
  782. #endif
  783. {
  784.     int    fld    = 0;        /* field number */
  785.     char *    p    = NULL;        /* gp char pointer */
  786.  
  787. #ifdef DEBUG
  788.     /* validate arguments */
  789.     if (fp == NULL || recname == NULL || fldc < 1 || fldv == NULL) {
  790.         errno = EINVAL;
  791.         return -1;
  792.     }
  793. #endif
  794.     /* record name */
  795.     fputs("/* record name */\n", fp);
  796.     fprintf(fp, "#define %s\t\"", tmpupr(recname));
  797.     if (fpdatafile(fp, recname) == -1) {
  798.         fprintf(stderr, "No data file name specified for record %s.\n", recname);
  799.         return -1;
  800.     }
  801.     fputs("\"\n\n", fp);
  802.  
  803.     /* extract identifier prefix from first field name */
  804.     strncpy(prefix, fldv[0].name, sizeof(prefix));
  805.     prefix[sizeof(prefix) - 1] = NUL;
  806.     p = strchr(prefix, '_');
  807.     if (p != NULL) {
  808.         *p = NUL;
  809.     }
  810.     cvtss(uprefix, prefix, CVT_UPPER, sizeof(uprefix));
  811.     uprefix[sizeof(uprefix) - 1] = NUL;
  812.  
  813.     /* record definition */
  814.     fprintf(fp, "/* %s record definition */\n", recname);
  815.     fprintf(fp, "typedef struct %s {\n", recname);
  816.     for (fld = 0; fld < fldc; ++fld) {
  817.         fputc('\t', fp);
  818.         fputs(fldv[fld].ctype, fp);
  819.         fprintf(fp, " %s", fldv[fld].name);
  820.         if (fldv[fld].elemc != NULL) {
  821.             fprintf(fp, "[%s]", fldv[fld].elemc);
  822.         }
  823.         fputs(";\n", fp);
  824.     }
  825.     fprintf(fp, "} %s_t;\n\n", recname);
  826.  
  827.     /* field names */
  828.     fprintf(fp, "/* field names for record %s */\n", recname);
  829.     for (fld = 0; fld < fldc; ++fld) {
  830.         fprintf(fp, "#define %s", tmpupr(fldv[fld].name));
  831.         if (strlen(fldv[fld].name) < 8) {    /* for tabs set at 8 */
  832.             fputc('\t', fp);
  833.         }
  834.         fprintf(fp, "\t(%d)\n", fld);
  835.     }
  836.     fprintf(fp, "#define %sFLDC\t\t(%d)\n\n", uprefix, fldc);
  837.  
  838.     /* field definition list declaration */
  839.     fprintf(fp, "/* field definition list for record %s */\n", recname);
  840.     fprintf(fp, "extern cbfield_t %sfldv[%sFLDC];\n\n", prefix, uprefix);
  841.  
  842.     return 0;
  843. }
  844.  
  845. /* ddlputi:  write to .i file */
  846. #ifdef AC_PROTO
  847. int ddlputi(FILE *fp, const char *recname, int fldc, const ddlfld_t fldv[])
  848. #else
  849. int ddlputi(fp, recname, fldc, fldv)
  850. FILE *fp;
  851. const char *recname;
  852. int fldc;
  853. const ddlfld_t fldv[];
  854. #endif
  855. {
  856.     int    fld    = 0;        /* field number */
  857.  
  858.     /* field definition list definition */
  859.     fprintf(fp, "/* field definition list for record %s */\n", recname);
  860.     fprintf(fp, "cbfield_t %sfldv[] = {\n", prefix);
  861.     for (fld = 0; fld < fldc; ++fld) {
  862.         fputs("\t{\n", fp);
  863.         fprintf(fp, "\t\toffsetof(struct %s, %s),\n", recname, fldv[fld].name);
  864.         fprintf(fp, "\t\tsizeofm(struct %s, %s),\n", recname, fldv[fld].name);
  865.         fprintf(fp, "\t\t%s,\n", fldv[fld].type);
  866.         if (fldv[fld].flags & CB_FKEY) {
  867.             fprintf(fp, "\t\tCB_FKEY");
  868.             if (fldv[fld].flags & CB_FUNIQ) {
  869.                 fprintf(fp, " | CB_FUNIQ");
  870.             }
  871.             fputs(",\n\t\t\"", fp);
  872.             if (fpndxfile(fp, fldv[fld].name) == -1) {
  873.                 fprintf(stderr, "No index file name specified for key %s.\n", fldv[fld].name);
  874.             }
  875.             fputs("\"\n", fp);
  876.         } else {
  877.             fputs("\t\t0,\n\t\tNULL\n", fp);
  878.         }
  879.         fprintf(fp, "\t},\n");
  880.     }
  881.     fprintf(fp, "};\n\n");
  882.  
  883.     return 0;
  884. }
  885.